#include <cstdlib>
#include <cstdio>
#include "music_if.hpp"
#include "simpleStack.hpp"
#include "sdram.hpp"
#include "ff.h"
#include "music.hpp"
#include "wm8978.hpp"

extern SAI_HandleTypeDef hsai_BlockA1;

static CString musicFolder = "0:/music/";           // 音乐文件夹
static constexpr uint32_t PLAY_BUFFER_SIZE = 512;  // 播放缓冲区大小
static uint8_t buf1[PLAY_BUFFER_SIZE];
static uint8_t buf2[PLAY_BUFFER_SIZE];
static volatile uint8_t playingBuf = 1;
static FIL fp;

void BeepVolume::setVolume(uint8_t vol)
{
    volume = vol >= 100 ? 100 : vol;
    setBeepVolume(volume * 63 / 100);
}

void PhoneVolume::setVolume(uint8_t vol)
{
    volume = vol >= 100 ? 100 : vol;
    setPhoneVolume(volume * 63 / 100);
}

void playMusic()
{
    // 使用双缓冲播放数据
    if (playingBuf == 1) {
        HAL_SAI_Transmit_DMA(&hsai_BlockA1, buf1, PLAY_BUFFER_SIZE / 2);
        f_read(&fp, buf2, PLAY_BUFFER_SIZE, nullptr);
        playingBuf = 2;
    } else {
        HAL_SAI_Transmit_DMA(&hsai_BlockA1, buf2, PLAY_BUFFER_SIZE / 2);
        f_read(&fp, buf1, PLAY_BUFFER_SIZE, nullptr);
        playingBuf = 1;
    }
}

// DMA 传输完成回调函数
void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
{
    if (!music_ctl->checkPaused()) [[likely]] {  // 恢复播放后需重新开启传输 playMusic
        playMusic();
    }
}

void adjustTim(uint16_t sec)
{
    music_t m = music_ctl->getPlayingMusic();
    f_lseek(&fp, m.offset + sec * m.bitPerSec);
}

void startPlayMusic()
{
    music_t music = music_ctl->getPlayingMusic();

    HAL_SAI_DMAPause(&hsai_BlockA1);
    
    f_open(&fp, (musicFolder + music.fileName).c_str(), FA_READ);
    f_lseek(&fp, music.offset);
    f_read(&fp, buf1, PLAY_BUFFER_SIZE, nullptr);
    playingBuf = 1;

    // printf("sample_rate: %d, bitPerSample: %d, numChannels: %d\n", music.sample_rate, music.bitsPerSample, music.numChannels);
    SAIA_SampleRate_Set(music.sample_rate);

    HAL_SAI_DMAResume(&hsai_BlockA1);

    playMusic();
}

// 加载文件 初始化音乐基本信息
// 1-19: 打开文件失败(FRESULT) 20: 文件格式错误 0: 成功
static uint8_t loadFile(const char *filename, music_t &music)
{
    FIL fp;
    if (auto res = f_open(&fp, filename, FA_READ)) {
        return res;
    }
    
    char *buff = (char *)memMalloc(500);
    f_read(&fp, buff, 500, nullptr);
    f_close(&fp);

    auto *head = (WAVHeader *)buff;
    auto *data = (Data *)(buff + music.offset);

    music.offset = 20 + head->subchunk1Size;
    music.sample_rate = head->sampleRate;
    music.bitsPerSample = head->bitsPerSample;
    music.numChannels = head->numChannels;

    // 查找 data 块
    for (; music.offset < 500; music.offset++) {
        bool flag = true;
        for (uint8_t t = 0; t < 4; t++) {
            if (buff[music.offset + t] != "data"[t]) {
                flag = false;
                break;
            }
        }
        if (flag) {
            // 双声道 16 位, 共 4 字节, 即 1s 数据大小为 4 * sample_rate
            music.bitPerSec = 4 * head->sampleRate;
            music.duration = data->dataSize / music.bitPerSec;
            memFree(buff);
            return 0;
        }
    }

    memFree(buff);
    return 20;
}

uint8_t loadFiles(CString folder)
{
    DIR dir;
    FILINFO fno;

    f_opendir(&dir, folder.c_str());
    FRESULT res = f_readdir(&dir, &fno);

    // 循环遍历该文件夹下的所有文件
    while (res == FR_OK && fno.fname[0]) {
        music_t music = {.fileName = fno.fname};
        CString fileName = (folder + fno.fname);
        if (loadFile(fileName.c_str(), music)) {
            continue;  // 文件格式错误
        }
        music_ctl->addMusic(music);

        // 读取下一个文件项
        res = f_readdir(&dir, &fno);
    }
    f_closedir(&dir);
    return 0;
}

static void playIndex(int16_t index)
{
    f_close(&fp);
    startPlayMusic();
}

uint16_t getRand()
{
    return rand() % music_ctl->size();
}